import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:obs_blade/shared/general/hive_builder.dart';
import 'package:obs_blade/shared/general/themed/cupertino_scaffold.dart';
import 'package:obs_blade/views/dashboard/screenshot_preview.dart';
import 'package:obs_blade/views/dashboard/widgets/dashboard_content/dashboard_content.dart';
import 'package:obs_blade/views/dashboard/widgets/dashboard_content/dashboard_content_streaming.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

import '../../shared/dialogs/confirmation.dart';
import '../../stores/shared/network.dart';
import '../../stores/views/dashboard.dart';
import '../../types/enums/hive_keys.dart';
import '../../types/enums/settings_keys.dart';
import '../../utils/modal_handler.dart';
import '../../utils/routing_helper.dart';
import 'widgets/dialogs/save_edit_connection.dart';
import 'widgets/reconnect_toast.dart';
import 'widgets/status_app_bar/status_app_bar.dart';

/// InheritedWidget [DashBoardScroll] is used to expose the ScrollController
/// which is being used for the main ListView in Dashboard to the descendant
/// Widgets - could be put inside the DashboardStore but I want to avoid
/// putting Flutter specific classes inside my stores
@Deprecated(
    'Don\'t necessary anymore since we expose a [ScrollController] from the Navigators used for the tabs since we want to scroll or route back if a user taps on the tab - therefore we can access the [ScrollController] from the [ModalRoute] settings argument')
class DashboardScroll extends InheritedWidget {
  final ScrollController scrollController = ScrollController();

  DashboardScroll({super.key, required super.child});

  static DashboardScroll of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<DashboardScroll>()!;

  @override
  bool updateShouldNotify(DashboardScroll oldWidget) =>
      oldWidget.scrollController != this.scrollController;
}

class DashboardView extends StatefulWidget {
  const DashboardView({
    super.key,
  });

  @override
  _DashboardViewState createState() => _DashboardViewState();
}

class _DashboardViewState extends State<DashboardView> {
  @override
  void initState() {
    super.initState();

    /// Since GetIt exposes stores in a global manner and I want a view
    /// store to be clean once a view is entered / inititalized, we need to
    /// reset them on every view (just in initState)
    GetIt.instance.resetLazySingleton<DashboardStore>();

    /// Initiate the [DashboardStore] object by initiating socket listeners
    /// and first calls etc.
    GetIt.instance<DashboardStore>().init();

    if (Hive.box(HiveKeys.Settings.name)
        .get(SettingsKeys.WakeLock.name, defaultValue: true)) {
      WakelockPlus.enable();
    }

    when(
      (_) =>
          GetIt.instance<NetworkStore>().activeSession!.connection.name == null,
      () => SchedulerBinding.instance.addPostFrameCallback(
        (_) => _saveConnectionDialog(context),
      ),
    );

    when(
      (_) => GetIt.instance<NetworkStore>().obsTerminated,
      () => SchedulerBinding.instance.addPostFrameCallback(
        (_) => Navigator.of(context).pushReplacementNamed(
          HomeTabRoutingKeys.Landing.route,
          arguments: ModalRoute.of(context)!.settings.arguments,
        ),
      ),
    );

    reaction(
      (_) =>
          GetIt.instance<DashboardStore>().manualScreenshotImageBytes != null,
      (_) => ModalHandler.showFullscreen(
        context: context,
        content: ScreenshotPreview(
          screenshotPath: GetIt.instance<DashboardStore>().screenshotPath,
          screenshot:
              GetIt.instance<DashboardStore>().manualScreenshotImageBytes!,
        ),
      ),
    );
  }

  @override
  void dispose() {
    /// Disable [Wakelock] - does not need to check whether this is active
    /// since calling disable is idempotent
    WakelockPlus.disable();
    super.dispose();
  }

  _saveConnectionDialog(BuildContext context) {
    ModalHandler.showBaseDialog(
      context: context,
      dialogWidget: ConfirmationDialog(
        title: 'Save Connection',
        body:
            'Do you want to save this connection? You can do it later as well!\n\n(Click on the icon on the top right of the screen and select "Save / Edit Connection"',
        onOk: (_) {
          Future.delayed(
            ModalHandler.transitionDelayDuration,
            () => ModalHandler.showBaseDialog(
              context: context,
              dialogWidget: const SaveEditConnectionDialog(),
            ),
          );
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final DashboardStore dashboardStore = GetIt.instance<DashboardStore>();

    return ThemedCupertinoScaffold(
      body: Stack(
        alignment: Alignment.topCenter,
        children: [
          HiveBuilder<dynamic>(
            hiveKey: HiveKeys.Settings,
            rebuildKeys: const [
              SettingsKeys.StreamingMode,
            ],
            builder: (context, settingsBox, child) => Observer(
              builder: (context) => CustomScrollView(
                physics: settingsBox.get(
                          SettingsKeys.StreamingMode.name,
                          defaultValue: false,
                        ) ||
                        dashboardStore.isPointerOnChat
                    ? const NeverScrollableScrollPhysics()
                    : const ClampingScrollPhysics(),
                controller: ModalRoute.of(context)!.settings.arguments
                    as ScrollController,
                slivers: [
                  const StatusAppBar(),
                  settingsBox.get(
                    SettingsKeys.StreamingMode.name,
                    defaultValue: false,
                  )
                      ? const DashboardContentStreaming()
                      : const DashboardContent(),
                ],
              ),
            ),
          ),
          Positioned(
            top: kToolbarHeight + MediaQuery.paddingOf(context).top,
            child: const Align(
              alignment: Alignment.center,
              child: FittedBox(
                fit: BoxFit.scaleDown,
                child: ReconnectToast(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
